/*
 * Copyright (c) 2014. Sensoro Inc.
 * All rights reserved.
 */

package com.sensoro.beacon.kit;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Sensoro on 14-6-23.
 */
public class BeaconService extends Service {
    public static final String TAG = BeaconService.class.getSimpleName();
    private static volatile long FOREGROUND_SCAN_PERIOD = SensoroBeaconManager.FOREGROUND_SCAN_PERIOD;
    private static volatile long FOREGROUND_BETWEEN_SCAN_PERIOD = SensoroBeaconManager.FOREGROUND_BETWEEN_SCAN_PERIOD;
    private static volatile long BACKGROUND_SCAN_PERIOD = SensoroBeaconManager.BACKGROUND_SCAN_PERIOD;
    private static volatile long BACKGROUND_BETWEEN_SCAN_PERIOD = SensoroBeaconManager.BACKGROUND_BETWEEN_SCAN_PERIOD;
    private volatile long scanPeriod = FOREGROUND_SCAN_PERIOD;
    private volatile long betweenScanPeriod = FOREGROUND_BETWEEN_SCAN_PERIOD;
    private BluetoothAdapter bluetoothAdapter;
    private Handler handler = new Handler();
    private volatile BeaconUpdateListener beaconUpdateListener = null;
    private ArrayList<Beacon> beacons = null;
    private boolean startService;

	private Map<String, Beacon> iBeaconMap;
	private Map<String, Beacon> e781Map;
    private HashMap<String,byte[]> broadcastKeyMap;

    private BluetoothCrashResolver bluetoothCrashResolver;

    public class BeaconBinder extends Binder {
        public BeaconService getService() {
            return BeaconService.this;
        }
    }

    @Override
    public void onCreate() {
        bluetoothCrashResolver = new BluetoothCrashResolver(this.getApplicationContext());
        getBluetoothAdapter();
        beacons = new ArrayList<Beacon>();
		iBeaconMap = new HashMap<String, Beacon>();
		e781Map = new HashMap<String, Beacon>();
		broadcastKeyMap = new HashMap<String,byte[]>();
        scanLeDevice(true);
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        if (SensoroBeaconManager.DEBUG) {
            Log.d(TAG, "onBind");
        }
        startService = true;
        return (IBinder) new BeaconBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        if (SensoroBeaconManager.DEBUG) {
            Log.d(TAG, "onUnbind");
        }
        startService = false;
		synchronized (iBeaconMap) {
			iBeaconMap.clear();
		}
		synchronized (e781Map) {
			e781Map.clear();
		}
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
//        Log.i(TAG, "onDestroy");
        scanLeDevice(false);
        if (bluetoothAdapter != null) {
            bluetoothAdapter.stopLeScan(leScanCallback);
        }
    }

    public void setBeaconUpdateListener(BeaconUpdateListener beaconUpdateListener) {
        this.beaconUpdateListener = beaconUpdateListener;
    }

    public void setForegroundScanPeriod(long foregroundScanPeriod) {
        FOREGROUND_SCAN_PERIOD = foregroundScanPeriod;
    }

    public void setForegroundBetweenScanPeriod(long foregroundBetweenScanPeriod) {
        FOREGROUND_BETWEEN_SCAN_PERIOD = foregroundBetweenScanPeriod;
    }

    public void setBackgroundScanPeriod(long backgroundScanPeriod) {
        BACKGROUND_SCAN_PERIOD = backgroundScanPeriod;
    }

    public void setBackgroundBetweenScanPeriod(long backgroundBetweenScanPeriod) {
        BACKGROUND_BETWEEN_SCAN_PERIOD = backgroundBetweenScanPeriod;
    }
    
    public void setBroadcastKeyMap(HashMap<String, byte[]> broadcastKeyMap) {
		synchronized (this.broadcastKeyMap) {
			this.broadcastKeyMap = broadcastKeyMap;
		}
	}

    public void setBackgroundMode(boolean backgroundMode) {
        Log.v(TAG, "background mode = " + backgroundMode);
        if (backgroundMode) {
            scanPeriod = BACKGROUND_SCAN_PERIOD;
            betweenScanPeriod = BACKGROUND_BETWEEN_SCAN_PERIOD;
        } else {
            scanPeriod = FOREGROUND_SCAN_PERIOD;
            betweenScanPeriod = FOREGROUND_BETWEEN_SCAN_PERIOD;
        }
    }

    private void scanLeDevice(final boolean enable) {
        if (bluetoothAdapter == null) {
            final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
            bluetoothAdapter = bluetoothManager.getAdapter();
        }
        if (enable) {
            bluetoothCrashResolver.start();
            // 开始扫描
            if (bluetoothAdapter != null) {
                try {
                    bluetoothAdapter.startLeScan(leScanCallback);
                } catch (Exception e){
                    bluetoothAdapter.startDiscovery();
                    try {
                        Thread.sleep(5000);
                        if (bluetoothAdapter.isDiscovering()){
                            bluetoothAdapter.cancelDiscovery();
                        }
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                }
            }

            // 预定义扫描周期之后停止扫描
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
//                    Log.v(TAG,"after "+ scanPeriod +" ms stop scan");
                    scanLeDevice(false);
                    if (beaconUpdateListener != null) {
                        ArrayList<Beacon> copyBeacons = (ArrayList<Beacon>) beacons.clone();
                        beaconUpdateListener.didBeacons(copyBeacons);
                    }
                    beacons.clear();

                    // 预定扫描间隔后重新扫描
                    handler.postDelayed(restartRunnable, betweenScanPeriod);
                }
            }, scanPeriod);
        } else {
            if (bluetoothAdapter != null) {
                try {
                    bluetoothCrashResolver.stop();
                    bluetoothAdapter.stopLeScan(leScanCallback);
                } catch (Exception e){
                    if (bluetoothAdapter.isDiscovering()){
                        bluetoothAdapter.cancelDiscovery();
                    }
                }
            }
        }
    }

    private BluetoothAdapter getBluetoothAdapter() {
        if (bluetoothAdapter == null) {
            // Initializes Bluetooth adapter.
            final BluetoothManager bluetoothManager = (BluetoothManager) this.getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE);
            bluetoothAdapter = bluetoothManager.getAdapter();
        }
        return bluetoothAdapter;
    }

    private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
            bluetoothCrashResolver.notifyScannedDevice(device, leScanCallback);
//            Log.e(TAG, "" + device.toString());
        	BeaconFactory beaconFactory = null;
        	synchronized (broadcastKeyMap) {
        		beaconFactory = new BeaconFactory(device.getAddress(), rssi, scanRecord, iBeaconMap, e781Map,broadcastKeyMap);
			}
			Beacon beacon = beaconFactory.createBeacon();
            if (beacon != null) {
                if (!beacons.contains(beacon)) {
                    beacons.add(beacon);
                }
            }
        }
    };

    //重启扫描服务线程
    private Runnable restartRunnable = new Runnable() {
        @Override
        public void run() {
//            Log.v(TAG,"between " + betweenScanPeriod +" ms,start scan");
            if (startService) {
                scanLeDevice(true);
            }
        }
    };
}